/*
 * 版权所有 (C) 2018 知启蒙(ZHIQIM) 保留所有权利。
 * 
 * 欢迎到知启蒙网站（https://www.zhiqim.com）购买正版软件，知启蒙还提供许多开源框架和软件。
 * 
 * 1、本软件产品所有源代码受《中华人民共和国著作权法》和其他有关法律、法规的保护，其所有知识产权归湖南知启蒙科技有限公司所有；
 * 2、禁止复制和修改。不得复制修改、翻译或改编本软件所有源代码，或者基于本软件产品创作衍生作品；
 * 3、禁止进行逆向工程。不得对本软件的源代码进行逆向工程、反编译或试图以其他方式发现软件的源代码；
 * 4、个别授权：如需进行商业性的销售、复制、分发，包括但不限于软件销售、预装、捆绑等，必须获得知启蒙的书面授权和许可；
 * 5、保留权利：本注释未明示授权的其他一切权利仍归知启蒙所有，任何人使用其他权利时必须获得知启蒙的书面同意。
 */
package net.redxyz.repost.service.dao;

import java.sql.SQLException;
import java.util.ArrayList;

import org.zhiqim.httpd.HttpHeader;
import org.zhiqim.kernel.Global;
import org.zhiqim.kernel.constants.ZhiqimConstants;
import org.zhiqim.kernel.httpclient.HttpResult;
import org.zhiqim.kernel.json.Jsons;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.schedule.Task;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Sqls;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.kernel.util.codes.MD5;
import org.zhiqim.orm.ORM;
import org.zhiqim.orm.ORMException;
import org.zhiqim.orm.ZTable;
import org.zhiqim.orm.ZView;
import org.zhiqim.orm.dbo.Selector;
import org.zhiqim.orm.dbo.Updater;

import net.redxyz.open.api.dbo.AppExpandUser;
import net.redxyz.open.api.dbo.AppExpandUserView;
import net.redxyz.top.TaobaoService;
import net.redxyz.top.data.vas.ArticleBizOrder;
import net.redxyz.top.data.vas.ArticleUserSubscribe;
import net.redxyz.top.dbo.sys.SysApp;
import net.redxyz.top.dbo.user.User;
import net.redxyz.top.dbo.user.UserApiErrorChain;
import net.redxyz.top.dbo.user.UserApiErrorInfo;
import net.redxyz.top.dbo.user.UserBlack;
import net.redxyz.top.dbo.user.UserError;
import net.redxyz.top.dbo.user.UserOrder;
import net.redxyz.top.dbo.user.UserWhite;
import net.redxyz.top.message.ErrorResponse;
import net.redxyz.top.message.TaobaoRequest;

/**
 * 用户相关数据访问对象
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class UserDao
{
    private static final Log log = LogFactory.getLog(UserDao.class);
    
    private static final String articleCode = Global.getString("taobao", "articleCode");// 收费编码
    private static long clear_error_api_time = System.currentTimeMillis();
    
    /*****************************************************/
    // 以下和用户相关
    /*****************************************************/
    
    /**获取用户剩余短信数量*/
    public static int getUserSmsCount(String nick)
    {
        try
        {
            User user = getUser(nick);
            return user.getUserSmsNum();
        }
        catch (Exception e)
        {
            
            e.printStackTrace();
            return 0;
        }
        
    }
    
    /**
     * 插入用户错误信息
     * 
     * @param nick          用户昵称
     * @param sessionId     会话编号
     * @param errorMessage  错误信息
     * @param lastLoginTime 最后登录时间
     */
    public static void addUserError(String nick, String sessionId, String errorMessage, String lastLoginTime)
    {
        UserError errorUser = new UserError();
        errorUser.setNick(nick);
        errorUser.setSessionId(sessionId);
        errorUser.setErrorMessage(errorMessage);
        errorUser.setCreateTime(DateTimes.getDateTimeString());
        errorUser.setLastLoginTime(lastLoginTime);
        
        try
        {
            ORM.table().replace(errorUser);
        }
        catch (Exception e)
        {
            log.error("更新用户错误信息时异常", e);
        }
    }
    
    /**
     * 插入用户API调用错误信息
     * @param loginTime     最后登录时间
     * @param nick          用户昵称
     * @param sessionId     会话编号
     * @param errorMessage  错误信息
     * @param lastLoginTime 最后登录时间
     * @throws SQLException 
     * @throws ORMException 
     */
    public static void addInvokeApiError(TaobaoRequest<?> req, ErrorResponse err, String loginTime) throws ORMException, SQLException
    {
        StackTraceElement[] elms = new Exception().getStackTrace();
        int limit = 2000, msg_limit = 4000, invockType = 0;
        StringBuilder strb = new StringBuilder(limit);
        for (int i = 3; i < elms.length; i++)
        {
            if (strb.length() >= limit)
                break;
            
            StackTraceElement elem = elms[i];
            strb.append(elem).append("\r\n");
            
            if (elem.getClassName() != null)
            {
                Class<?> clz = Classes.forName(elem.getClassName());
                if (clz != null)
                {
                    
                    if (HttpHeader.class.isAssignableFrom(clz))
                    {
                        invockType = 1;// http
                    }
                    else if (Task.class.isAssignableFrom(clz))
                    {
                        invockType = 2;// task
                    }
                }
            }
        }
        
        long cur = System.currentTimeMillis();
        if (cur - clear_error_api_time > 86400 * 15)
        {// 每天清理 15天前的错误信息
            clear_error_api_time = cur;
            try
            {
                ORM.table().delete(UserApiErrorChain.class, new Selector().addMustThenL("dayDate", DateTimes.getPreviousDateString(15)));
                
                ORM.table().delete(UserApiErrorChain.class, new Selector().addMustThenL("createTime", DateTimes.getPreviousDateTimeString(15)));
            }
            catch (Exception e)
            {
               
            }
        }
        
        // 保存栈信息链路
        String systemName = Global.getString(ZhiqimConstants.Z_BOOT, "process");
        if (systemName == null)
            systemName = Global.getName();
        
        StringBuilder strb2 = new StringBuilder(limit);
        strb2.append(strb.toString());// 加入站调用信息
        strb2.append("_" + DateTimes.getDateString());// 加入日期
        strb2.append("_" + systemName);// 加入系统名
        strb2.append("_" + req.getMethod());// 加入 API
        String chainId = MD5.encodeUTF8(strb2.toString());
        UserApiErrorChain chain = ORM.table().item(UserApiErrorChain.class, chainId);
        if (chain != null)
        {
            ORM.table().update(UserApiErrorChain.class, new Updater().addMust("chainId", chainId).addField("apiCount", chain.getApiCount() + 1));
        }
        else
        {
            try
            {
                chain = new UserApiErrorChain();
                chain.setChainId(chainId);
                chain.setDayDate(DateTimes.getDateString());
                chain.setApiCount(1);
                chain.setApiName(req.getMethod());
                chain.setInvockStack(strb.toString());
                chain.setInvockType(invockType);
                chain.setSystemName(systemName);
                ORM.table().insert(chain);
            }
            catch (Exception e)
            {
                return;
            }
        }
        
        // 添加错误详细信息
        UserApiErrorInfo api = new UserApiErrorInfo();
        api.setChainId(chainId);
        api.setApiName(req.getMethod());
        api.setCode(err.getCode());
        api.setCreateTime(Sqls.nowTimestamp());
        api.setErrorMsg(err.getMsg());
        api.setLastLoginTime(loginTime);
        api.setSessionId(req.getSession());
        api.setSubCode(err.getSubCode());
        api.setSubMessage(err.getSubMsg() == null ? null : (err.getSubMsg().length() <= msg_limit ? err.getSubMsg() : err.getSubMsg().substring(0, msg_limit)));
        api.setUserNick(req.getNick());
        api.setRequestInfo(Jsons.toString(req.getParameterMap()));
        try
        {
            ORM.table().insert(api);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        };
    }
    
    /** 关闭到期用户，只关闭消息服务和修改用户状态为已关闭 */
    public static void doCloseUser(String nick)
    {
        if (Validates.isEmptyBlank(nick))
            return;
        
        try
        {
            //1.关闭用户JDP消息&TMC消息
            SyncDao.doCloseSync(nick);
            
            //2.修改用户状态
            Updater updater = new Updater();
            updater.addMust("nick", nick);
            updater.addField("userStatus", 1);
            ORM.table().update(User.class, updater);

            log.info("到期用户[" + nick + "]关闭完成");
        }
        catch (Exception e)
        {
            log.error("到期用户[" + nick + "]关闭失败", e);
        }
    }
    
    /** 关闭到期用户，只关闭消息服务和修改用户状态为已关闭 */
    public static void doCloseUser(User user)
    {
        if (user == null)
            return;
        
        doCloseUser(user.getNick());
    }
    
    /*****************************************************/
    // 以下和订购关系相关
    /*****************************************************/
    
    /** 
     * 获取用户最近订购信息 
     * @param nick 用户昵称
     * @param maxTimes 查询次数
     * @return
     * @throws Exception
     */
    public static ArticleUserSubscribe getUserOrder(String nick, int maxTimes) throws Exception
    {
        ArticleUserSubscribe subscribe = TaobaoService.getVasService().getSubscribeVas(articleCode, nick);
        if (!subscribe.isSuccess())
        {
            int times = 0;
            while (subscribe.getStatus() == ArticleUserSubscribe.UNKNOWN && times < maxTimes)
            {// 当查询失败时最多重查maxTimes次,每次停1秒
                times++;
                Thread.sleep(1001);
                subscribe = TaobaoService.getVasService().getSubscribeVas(articleCode, nick);
            }
            
            return subscribe;
        }
        
        // 如果成功,则到系统查找版号
        int versionNo = ArticleDao.getVersionNo(subscribe.getItemCode());
        subscribe.setVersionNo(versionNo);
        return subscribe;
    }
    
    /**
     * 刷新用户授权，并更新用户版本号和到期日期
     * 
     * @param user          用户信息
     * @param versionNo     版本号
     * @param endDate       到期日期
     * @return              返回成功或失败的描述
     */
    public static String doRefreshToken(User user, int versionNo, String endDate)
    {
        // 重授权
        String curDate = DateTimes.getDateString();
        String refreshToken = user.getRefreshToken();
        HttpResult result = TaobaoService.refreshToken(refreshToken);
        if (!result.isSuccess())
        {
            String error = "重授权用户[" + curDate + "][" + user.getNick() + "]，读取OAuth时失败:responseStat=" + result.getResponseStatus();
            log.error(error);
            
            addUserError(user.getNick(), user.getSessionId(), error, user.getLastLoginTime());
            return error;
        }
        
        String sessionToken = result.getResponseText();
        if (Validates.isEmpty(sessionToken))
        {
            String error = "重授权用户[" + curDate + "][" + user.getNick() + "]，读取OAuth时失败:sessionToken为空";
            log.error(error);
            
            addUserError(user.getNick(), user.getSessionId(), error, user.getLastLoginTime());
            return error;
        }
        
        sessionToken = Jsons.removeBlankSpace(sessionToken);// 去除一下空字符串再保存到数据库
        
        String userId = Jsons.getString(sessionToken, "taobao_user_id");
        String nick = Jsons.getString(sessionToken, "taobao_user_nick");
        
        String sessionId = Jsons.getString(sessionToken, "access_token");
        int expiresIn = Jsons.getInt(sessionToken, "expires_in");
        int expiresInR1 = Jsons.getInt(sessionToken, "r1_expires_in");
        int expiresInR2 = Jsons.getInt(sessionToken, "r2_expires_in");
        int expiresInW1 = Jsons.getInt(sessionToken, "w1_expires_in");
        int expiresInW2 = Jsons.getInt(sessionToken, "w2_expires_in");
        
        refreshToken = Jsons.getString(sessionToken, "refresh_token");
        int reExpiresIn = Jsons.getInt(sessionToken, "re_expires_in");
        
        if (Validates.isEmpty(userId) || Validates.isEmpty(nick))
        {
            String error = "重授权用户[" + curDate + "][" + user.getNick() + "]，解析淘宝参数时未找到用户编号或用户昵称";
            log.error(error);
            return error;
        }
        
        if (Validates.isEmpty(sessionId) || Validates.isEmpty(refreshToken) || expiresIn == -1 || expiresInR1 == -1
                || expiresInR2 == -1 || expiresInW1 == -1 || expiresInW2 == -1 || reExpiresIn == -1)
        {
            String error = "重授权用户[" + curDate + "][" + user.getNick() + "]，解析淘宝参数时未找到accessToken或refreshToken数据:[" + user.getNick() + "]";
            log.error(error);
            return error;
        }
        
        try
        {
            String time = DateTimes.getDateTimeString();
            Updater updater = new Updater();
            updater.addMust("nick", user.getNick());
            updater.addField("versionNo", versionNo);
            updater.addField("endDate", endDate);
            updater.addField("userStatus", 0);// 正常
            
            updater.addField("sessionId", sessionId);
            updater.addField("sessionTime", time);
            updater.addField("sessionToken", sessionToken);
            updater.addField("expiresIn", expiresIn);
            updater.addField("expiresInR1", expiresInR1);
            updater.addField("expiresInR2", expiresInR2);
            updater.addField("expiresInW1", expiresInW1);
            updater.addField("expiresInW2", expiresInW2);
            updater.addField("refreshToken", refreshToken);
            updater.addField("reExpiresIn", reExpiresIn);
            
            updateUser(user.getNick(), updater);
            
            log.info("重授权用户[" + user.getNick() + "]到期日[" + endDate + "]，重授权成功");
        }
        catch (Exception e)
        {
            log.error("重授权用户[" + user.getNick() + "]到期日[" + endDate + "]，更新数据库失败");
        }
        
        return "授权成功";
    }
    
    /**
     * 更新指定用户的订单
     * 
     * @param nick          用户昵称
     * @throws Exception    异常
     */
    public static void doUpdateOrder(String nick) throws Exception
    {
        boolean hasRenewal = false;
        int maxVersionNo = 0;
        ArrayList<ArticleBizOrder> orderList = TaobaoService.getVasService().getOrderList(articleCode, nick);
        for (ArticleBizOrder order : orderList)
        {
            UserOrder uOrder = new UserOrder();
            uOrder.setBeginTime(order.getOrderCycleStart());
            uOrder.setBizOrderId(order.getBizOrderId());
            uOrder.setBizType(order.getBizType());
            uOrder.setEndTime(order.getOrderCycleEnd());
            uOrder.setFee(order.getFee());
            uOrder.setNick(order.getNick());
            uOrder.setOrderCycle(order.getOrderCycle());
            uOrder.setOrderId(order.getOrderId());
            uOrder.setOrderTime(order.getCreate());
            uOrder.setPromFee(order.getPromFee());
            uOrder.setRefundFee(order.getRefundFee());
            uOrder.setTotalPayFee(order.getTotalPayFee());
            
            String itemCode = order.getItemCode();
            int versionNo = ArticleDao.getVersionNo(itemCode);
            if (versionNo > maxVersionNo)
                maxVersionNo = versionNo;
            
            uOrder.setVersionNo(versionNo);
            uOrder.setItemCode(itemCode);
            
            ORM.table().replace(uOrder);
            
            if (order.getBizType() == 2 || order.getBizType() == 5)
                hasRenewal = true;
        }
        
        // 对续费用户要求作续费检查
        if (hasRenewal)
            doChkRenewal(nick);
    }
    
    /**
     * 更新指定时间段的订单
     * 
     * @param beginTime     开始时间
     * @param endTime       结束时间
     * @return              返回查询到的订单条数
     * @throws Exception    异常
     */
    public static int doUpdateOrder(String beginTime, String endTime) throws Exception
    {
        ArrayList<ArticleBizOrder> orderList = TaobaoService.getVasService().getOrderList(articleCode, beginTime, endTime);
        for (ArticleBizOrder order : orderList)
        {
            UserOrder uOrder = new UserOrder();
            uOrder.setBizType(order.getBizType());
            uOrder.setBizOrderId(order.getBizOrderId());
            uOrder.setOrderId(order.getOrderId());
            uOrder.setOrderCycle(order.getOrderCycle());
            uOrder.setOrderTime(order.getCreate());
            uOrder.setNick(order.getNick());
            uOrder.setBeginTime(order.getOrderCycleStart());
            uOrder.setEndTime(order.getOrderCycleEnd());
            uOrder.setFee(order.getFee());
            uOrder.setPromFee(order.getPromFee());
            uOrder.setRefundFee(order.getRefundFee());
            uOrder.setTotalPayFee(order.getTotalPayFee());
            
            String itemCode = order.getItemCode();
            int versionNo = ArticleDao.getVersionNo(itemCode);
            
            uOrder.setVersionNo(versionNo);
            uOrder.setItemCode(itemCode);
            
            doUpdateOrder(uOrder);
        }
        
        return orderList.size();
    }
    
    /**
     * 更新指定的订单
     * 
     * @param order         订单
     * @throws Exception    异常
     */
    public static void doUpdateOrder(UserOrder order) throws Exception
    {
        ORM.table().replace(order);
        
        if (order.getBizType() == 2 || order.getBizType() == 5)
        {// 对续费用户要求作续费检查
            doChkRenewal(order.getNick());
        }
    }
    
    /**
     * 检查用户续费情况
     * 
     * @param nick  用户昵称
     * @return      返回成功或失败的描述
     */
    public static String doChkRenewal(String nick)
    {
        try
        {
            // 第一，查用户信息
            User user = getUser(nick);
            if (user == null)
            {
                log.error("查询订购关系任务，检查续费授权，查询用户[" + nick + "]不存在");
                return "查询用户时不存在";
            }
            
            // 第二，查询订购关系，查看是否真正到期
            ArticleUserSubscribe subscribe = getUserOrder(nick, 1);
            switch (subscribe.getStatus())
            {
                case ArticleUserSubscribe.UNKNOWN:
                {// 查询失败
                    log.error("查询订购关系任务，检查续费授权，查询用户[" + nick + "]订购关系失败，下次重试");
                    return "查询用户订购关系失败，请重试";
                }
                case ArticleUserSubscribe.EXPIRE:
                {// 用户直接到期或无效
                    doCloseUser(user);
                    log.info("查询订购关系任务，检查续费授权，用户[" + nick + "]关闭成功");
                    return "查询用户订购关系时，用户已到期，关闭用户成功";
                }
                case ArticleUserSubscribe.SUCCESS:
                {// 订购关系正确，即更新订购关系并重授权
                    int versionNo = subscribe.getVersionNo();
                    String endDate = subscribe.getEndDate();
                    
                    doRefreshToken(user, versionNo, endDate);
                    return "检查续费成功，并重授权";
                }
                default:
                    return "检查续费时未知状态";
            }
        }
        catch (Exception e)
        {
            log.error("续费授权检查任务异常", e);
            return "检查续费操作时异常，请重试";
        }
        finally
        {
            try
            {
                Thread.sleep(997);
            }
            catch (InterruptedException e)
            {}
        }
    }
    
    /*****************************************************/
    // 以下和授权相关
    /*****************************************************/
    
    /**
     * 验证用户授权是否有效
     * 
     * @param user  用户信息
     * @return      =true表示有效,=false表示无效
     */
    public static boolean isAccredit(User user)
    {
        if (user == null)
            return false;
        
        int expireIn = user.getExpiresIn();
        String sessionTime = user.getSessionTime();
        
        return isAccredit(sessionTime, expireIn);
    }
    
    /**
     * 验证用户授权是否有效
     * 
     * @param sessionTime   用户会话开始时间
     * @param expireIn      用户会话有效秒数
     * @return              =true表示有效,=false表示无效
     */
    public static boolean isAccredit(String sessionTime, int expireIn)
    {
        String datetime = DateTimes.getDateTimeString();
        String sessionExpire = DateTimes.getNextDateTimeStringBySecond(sessionTime, expireIn);
        if (datetime.compareTo(sessionExpire) >= 0)
            return false;
        else
            return true;
    }
    
    /**更新用户积分**/
    public static void updatePoint(String nick, long userPoint) throws Exception
    {
        Updater updater = new Updater();
        updater.addMust("nick", nick);
        updater.addField("userPoint", userPoint);
        
        updateUser(nick, updater);
    }
    
    /**更新用户信息**/
    public static void updateUserStatus(String nick, int userStatus, String dateTime) throws Exception
    {
        Updater updater = new Updater();
        updater.addMust("nick", nick);
        updater.addField("userStatus", userStatus);
        updater.addField("lastLoginTime", dateTime);
        
        updateUser(nick, updater);
    }
    
    /**更新用户短信数**/
    public static void updateUserSmsNum(String nick, int userSmsNum) throws Exception
    {
        Updater updater = new Updater();
        updater.addMust("nick", nick);
        updater.addField("userSmsNum", userSmsNum);
        
        updateUser(nick, updater);
    }
    
    /**更新用户版本**/
    public static void updateUserVersion(String nick, int versionNo, String endDate) throws Exception
    {
        Updater updater = new Updater();
        updater.addMust("nick", nick);
        updater.addField("versionNo", versionNo);
        updater.addField("endDate", endDate);
        
        updateUser(nick, updater);
    }
    
    /** 获取用户信息 */
    public static User getUser(String nick) throws Exception
    {
        return ORM.table().item(User.class, nick);
    }
    
    /**更新用户信息*/
    public static void updateUser(String nick, Updater updater) throws Exception
    {
        ORM.table().update(User.class, updater);
    }
    
    /**添加用户信息*/
    public static void addUser(User user) throws Exception
    {
        ORM.table().insert(user);
    }
    
    /**替换用户信息*/
    public static void replaceUser(User user) throws Exception
    {
        ORM.table().replace(user);
    }
    
    /**删除用户*/
    public static void deleteUser(String nick) throws Exception
    {
        ORM.table().delete(User.class, nick);
    }
    

    /**
     * 判断用户是否为开放API指发展的用户<br>
     * 这里需要 appKey 状态为可用并且才可能返回正确值
     * 
     * @param appKey 开放appKey
     * @param nick 用户昵称
     * @return true|false
     * @throws Exception
     */
    public static boolean isAppExpandUser(long appKey, String nick) throws Exception {
        if (Validates.isEmptyBlank(nick) || appKey <= 0)
            return false;
        
        Selector sel = new Selector();
        sel.addMust("appKey", appKey);
        sel.addMust("nick", nick);
        sel.addMust("appStatus", 0);
        
        AppExpandUserView user = getAppExpandUser(appKey, nick);
        return user != null && user.getAppStatus() == 0;
    }
    
    /**
     * 获取开放API 发展用户，注意 app不可用是返回null
     * 
     * @param appKey
     * @param nick
     * @throws Exception
     */
    public static AppExpandUserView getAppExpandUser(long appKey, String nick) throws Exception {
        if (Validates.isEmptyBlank(nick) || appKey <= 0)
            return null;
        Selector sel = new Selector();
        sel.addMust("appKey", appKey);
        sel.addMust("appStatus", 0);// 3.应用状态：0表示正常
        sel.addMust("nick", nick);
        return ORM.get(ZView.class).item(AppExpandUserView.class, sel);
    }
    
    /**
     * 新增app发展用户
     * 
     * @param appKey
     * @param nick
     * @return
     */
    public static AppExpandUser addAppExpandUser(long appKey, String nick) throws Exception {
        SysApp app = null;
        if (appKey > 0)
            app = ORM.get(ZTable.class).item(SysApp.class, new Selector("appKey", appKey).addMust("appStatus", 0));
        if (app == null)
            throw new RuntimeException("应用不存在，或者停用，不允许新增发展用户");
        
        if (Validates.isEmptyBlank(nick))
            throw new RuntimeException("用户账号不能为空白，且不能超过50字符");
        
        AppExpandUser user = ORM.get(ZTable.class).item(AppExpandUser.class, new Selector("appKey", appKey).addMust("nick", Strings.trim(nick)));
        if (user != null) {
            return user;
        } else {
            user = new AppExpandUser();
            user.setAppKey(app.getAppKey());
            user.setNick(nick);
            ORM.get(ZTable.class).insert(user);
        }
        
        return user;
    }
    
    /**
     * 添加黑名单用户 已添加白名单的无效
     * @param nick
     * @param desc
     * @return true|false 当用户为白名单时 返回false
     * @throws Exception
     */
    public static boolean addBlackUser(String nick, String desc) throws Exception {
        if (isWhiteUser(nick)) {
            return false;
        }
        
        if (isBlackUser(nick)) {
            return true;
        }
        
        UserBlack b = new UserBlack();
        b.setNick(nick);
        b.setOperateDesc(desc);
        b.setCreateTime(DateTimes.getDateTimeString());
        ORM.get(ZTable.class).insert(b);
        return true;
    }
    
    /**
     * 删除黑名单用户
     * 
     * @param nick 用户昵称
     * @param desc 黑名单备注。
     * @throws Exception
     */
    public static void removeBlackUser(String nick) throws Exception {
        ORM.get(ZTable.class).delete(UserBlack.class, new Selector("nick", nick));
    }
    
    
    /** 判断是否为黑名单用户 */
    public static boolean isBlackUser(String nick) throws Exception {
        return Validates.isEmptyBlank(nick) ? false : ORM.get(ZTable.class).item(UserBlack.class, new Selector("nick").addMust("nick", nick)) != null;
    }
    
    
    /**
     * 判断用户是否为白名单用户
     * 
     * @param nick 用户账号
     * @return
     */
    public static boolean isWhiteUser(String nick) throws Exception {
        if (Validates.isEmptyBlank(nick))
            return false;
        
        return ORM.table().item(UserWhite.class, new Selector("nick,createTime").addMust("nick", Strings.trim(nick))) != null;
    }
}
